#include "Layout_ex.h"

BOOL _layout_register(INT nType, LayoutPROC lpfnLayoutProc)
{
    BOOL ret = FALSE;
    if (!HashTable_IsExist(g_Li.hTableLayout, nType))
    {
        ret = HashTable_Set(g_Li.hTableLayout, nType, (size_t)lpfnLayoutProc);
    }
    return ret;
}

BOOL _layout_unregister(INT nType)
{
    BOOL ret = FALSE;
    if (!HashTable_IsExist(g_Li.hTableLayout, nType))
    {
        ret = HashTable_Remove(g_Li.hTableLayout, nType);
    }
    return ret;
}

void _layout_free_info(array_s *hArr, INT nIndex, LPVOID pvItem, INT nType)
{
    layout_s *pLayout = (layout_s *)Array_GetExtra(hArr);
    ((LayoutPROC)pLayout->lpfnProc_)(pLayout, ELN_UNINITCHILDPROPS, __get(pvItem, 0), (size_t)pvItem);
    Ex_MemFree((LPVOID)((size_t)pvItem - 4 * sizeof(size_t)));
}

HEXLAYOUT _layout_create(INT nType, EXHANDLE hObjBind)
{
    HEXLAYOUT hLayout = 0;
    INT nError = 0;
    if (nType > 0 && hObjBind != 0)
    {
        size_t lpfnProc = 0;
        HashTable_Get(g_Li.hTableLayout, nType, &lpfnProc);
        if (lpfnProc != 0)
        {
            layout_s *pLayout = (layout_s *)Ex_MemAlloc(sizeof(layout_s));
            obj_s *pObj = nullptr;
            if (pLayout != 0)
            {
                if (_handle_validate(hObjBind, HT_OBJECT, (LPVOID *)&pObj, &nError))
                {
                    pLayout->nBindType_ = HT_OBJECT;
                }
                else if (_handle_validate(hObjBind, HT_DUI, (LPVOID *)&pObj, &nError))
                {
                    pLayout->nBindType_ = HT_DUI;
                }
                else
                {
                    nError = ERROR_EX_INVALID_OBJECT;
                }
                if (nError == 0)
                {
                    pLayout->nType_ = nType;
                    pLayout->fUpdateable_ = TRUE;
                    pLayout->lpfnProc_ = (LPVOID)lpfnProc;
                    pLayout->hBind_ = hObjBind;
                    INT nCount = ((LayoutPROC)lpfnProc)(pLayout, ELN_GETPROPSCOUNT, NULL, NULL);
                    LPVOID pInfo = (LPVOID)((size_t)Ex_MemAlloc((nCount + (size_t)4) * sizeof(size_t)) + (size_t)4 * sizeof(size_t)); //padding
                    pLayout->lpLayoutInfo_ = pInfo;
                    ((LayoutPROC)lpfnProc)(pLayout, ELN_INITPROPS, NULL, (size_t)pInfo);
                    nCount = ((LayoutPROC)lpfnProc)(pLayout, ELN_GETCHILDPROPCOUNT, NULL, NULL);
                    pLayout->cbInfoLen_ = (nCount + 5) * sizeof(size_t); // Margin4/hObjChild1
                    array_s *hArr = Array_Create(0);
                    Array_BindEvent(hArr, eae_delmember, &_layout_free_info);
                    Array_SetExtra(hArr, (size_t)pLayout);
                    pLayout->hArrChildrenInfo_ = hArr;
                    hLayout = _handle_create(HT_LAYOUT, pLayout, &nError);
                    pLayout->hLayout_ = hLayout;
                    ((obj_s *)pObj)->hLayout_ = hLayout;
                }
                else
                {
                    Ex_MemFree(pLayout);
                }
            }
            else
            {
                nError = ERROR_EX_MEMORY_ALLOC;
            }
        }
        else
        {
            nError = ERROR_EX_LAYOUT_INVALID;
        }
    }
    else
    {
        nError = ERROR_EX_LAYOUT_INVALID;
    }
    Ex_SetLastError(nError);
    return hLayout;
}

HEXLAYOUT _layout_get_parent_layout(HEXOBJ hObj)
{
    INT nError = 0;
    obj_s *pObj = nullptr;
    HEXLAYOUT hLayoutParent = 0;
    if (_handle_validate(hObj, HT_OBJECT, (LPVOID *)&pObj, &nError))
    {
        EXHANDLE hObj = pObj->objParent_;
        if (hObj == 0)
        {
            wnd_s *pWnd = pObj->pWnd_;
            hObj = pWnd->hexdui_;
        }
        hLayoutParent = Ex_ObjLayoutGet(hObj);
    }
    return hLayoutParent;
}

BOOL _layout_destroy(HEXLAYOUT hLayout)
{
    INT nError = 0;
    layout_s *pLayout = nullptr;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        LPVOID lpfnProc = pLayout->lpfnProc_;
        ((LayoutPROC)lpfnProc)(pLayout, ELN_UNINITPROPS, 0, (size_t)pLayout->lpLayoutInfo_);
        Array_Destroy(pLayout->hArrChildrenInfo_);
        Ex_MemFree((LPVOID)((size_t)pLayout->lpLayoutInfo_ - 4 * sizeof(size_t)));
        Ex_MemFree(pLayout);
        nError = 0;
        _handle_destroy(hLayout, &nError);
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

BOOL _layout_enum_find_obj(LPVOID hArr, INT nIndex, LPVOID pvItem, INT nType, size_t pvParam)
{
    return (__get(pvItem, 0) == pvParam);
}

LPVOID _layout_get_child(layout_s *pLayout, HEXOBJ hObj)
{
    EXHANDLE hObjP = pLayout->hBind_;
    HEXDUI hExDUI = 0;
    LPVOID pInfo = nullptr;
    if (Ex_ObjGetParentEx(hObj, &hExDUI) == hObjP || hExDUI == hObjP)
    {
        array_s *hArr = pLayout->hArrChildrenInfo_;
        INT nIndex = Array_Emum(hArr, &_layout_enum_find_obj, hObj);
        if (nIndex > 0)
        {
            pInfo = (LPVOID)Array_GetMember(hArr, nIndex);
        }
    }
    return pInfo;
}

BOOL _layout_update(HEXLAYOUT hLayout)
{
    INT nError = 0;
    layout_s *pLayout = nullptr;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        if (pLayout->fUpdateable_)
        {
            LPVOID lpfnProc = pLayout->lpfnProc_;
            ((LayoutPROC)lpfnProc)(pLayout, ELN_UPDATE, pLayout->hBind_, 0);
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

INT _layout_gettype(HEXLAYOUT hLayout)
{
    INT nError = 0;
    layout_s *pLayout = nullptr;
    INT nType = 0;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        nType = pLayout->nType_;
    }
    Ex_SetLastError(nError);
    return nType;
}

BOOL _layout_enableupdate(HEXLAYOUT hLayout, BOOL fUpdateable)
{
    INT nError = 0;
    layout_s *pLayout = nullptr;
    INT nType = 0;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        pLayout->fUpdateable_ = fUpdateable;
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

LRESULT _layout_notify(HEXLAYOUT hLayout, INT nEvent, WPARAM wParam, LPARAM lParam)
{
    INT nError = 0;
    layout_s *pLayout = nullptr;
    LRESULT ret = 1;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        if (pLayout->fUpdateable_)
        {
            LPVOID lpfnProc = pLayout->lpfnProc_;
            ret = ((LayoutPROC)lpfnProc)(pLayout, nEvent, (size_t)wParam, (size_t)lParam);
        }
    }
    Ex_SetLastError(nError);
    return ret;
}

BOOL _layout_table_setinfo(HEXLAYOUT hLayout, INT *aRowHeight, INT cRows, INT *aCellWidth, INT cCells)
{
    INT nError = 0;
    layout_s *pLayout = nullptr;
    INT ret = 1;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        if (pLayout->nType_ == ELT_TABLE)
        {
            LPVOID pInfo = pLayout->lpLayoutInfo_;
            array_s *hArr = (array_s *)__get(pInfo, (ELP_TABLE_ARRAY_ROW - 1) * sizeof(LPVOID));
            Array_Redefine(hArr, cRows, FALSE);
            for (INT i = 1; i <= cRows; i++)
            {
                Array_SetMember(hArr, i, aRowHeight[i - 1]);
            }
            hArr = (array_s *)__get(pInfo, (ELP_TABLE_ARRAY_CELL - 1) * sizeof(LPVOID));
            Array_Redefine(hArr, cCells, FALSE);
            for (INT i = 1; i <= cCells; i++)
            {
                Array_SetMember(hArr, i, aCellWidth[i - 1]);
            }
        }
        else
        {
            nError = ERROR_EX_LAYOUT_INVALID;
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

BOOL _layout_setchildprop(HEXLAYOUT hLayout, HEXOBJ hObj, INT dwPropID, size_t pvValue)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        if (hObj != 0)
        {
            array_s *hArr = pLayout->hArrChildrenInfo_;
            size_t nIndex = Array_Emum(hArr, &_layout_enum_find_obj, hObj);
            LPVOID pInfo = nullptr;
            if (nIndex == 0)
            {
                pInfo = Ex_MemAlloc(pLayout->cbInfoLen_);
                if (pInfo != 0)
                {
                    pInfo = (LPVOID)((size_t)pInfo + 4 * sizeof(size_t));
                    __set(pInfo, 0, hObj);
                    ((LayoutPROC)pLayout->lpfnProc_)(pLayout, ELN_INITCHILDPROPS, hObj, (size_t)pInfo);
                    nIndex = Array_AddMember(hArr, (size_t)pInfo);
                }
            }
            else
            {
                pInfo = (LPVOID)Array_GetMember(hArr, nIndex);
            }
            if (pInfo != 0)
            {

                if (((LayoutPROC)pLayout->lpfnProc_)(pLayout, ELN_CHECKCHILDPROPVALUE, MAKELONG(nIndex, dwPropID), pvValue) == 0)
                {

                    __set(pInfo, dwPropID * sizeof(size_t), pvValue);
                }
            }
            else
            {
                nError = ERROR_EX_MEMORY_ALLOC;
            }
        }
        else
        {
            nError = ERROR_EX_INVALID_OBJECT;
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

BOOL _layout_getchildprop(HEXLAYOUT hLayout, HEXOBJ hObj, INT dwPropID, size_t *pvValue)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        array_s *hArr = pLayout->hArrChildrenInfo_;
        size_t nIndex = Array_Emum(hArr, &_layout_enum_find_obj, hObj);
        LPVOID pInfo = nullptr;
        if (nIndex > 0)
        {
            pInfo = (LPVOID)Array_GetMember(hArr, nIndex);
        }
        if (pInfo != 0)
        {
            dwPropID = dwPropID * sizeof(LPVOID);
            if (dwPropID >= -16 && dwPropID < pLayout->cbInfoLen_)
            {
                *pvValue = __get(pInfo, dwPropID);
            }
            else
            {
                nError = ERROR_EX_LAYOUT_UNSUPPORTED_PROP;
            }
        }
        else
        {
            nError = ERROR_EX_LAYOUT_INVALID;
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

BOOL _layout_setprop(HEXLAYOUT hLayout, INT dwPropID, size_t pvValue)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        LPVOID pInfo = pLayout->lpLayoutInfo_;
        LPVOID lpfnProc = pLayout->lpfnProc_;
        if (((LayoutPROC)lpfnProc)(pLayout, ELN_CHECKCHILDPROPVALUE, dwPropID, pvValue) == 0)
        {
            if (dwPropID > 0)
            {
                dwPropID = dwPropID - 1;
            }
            __set(pInfo, dwPropID * sizeof(size_t), pvValue);
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

size_t _layout_getprop(HEXLAYOUT hLayout, INT dwPropID)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    size_t ret = 0;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        LPVOID pInfo = pLayout->lpLayoutInfo_;
        if (dwPropID > 0)
        {
            dwPropID = dwPropID - 1;
        }
        ret = __get(pInfo, dwPropID * sizeof(size_t));
    }
    Ex_SetLastError(nError);
    return ret;
}

BOOL _layout_absolute_setedge(HEXLAYOUT hLayout, HEXOBJ hObjChild, INT dwEdge, INT dwType, size_t nValue)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        if (pLayout->nType_ == ELT_ABSOLUTE)
        {
            dwEdge = (dwEdge + 1) / 2;
            if (dwEdge >= 1 && dwEdge <= 8)
            {
                _layout_setchildprop(hLayout, hObjChild, dwEdge * 2, dwType);
                _layout_setchildprop(hLayout, hObjChild, dwEdge * 2 - 1, nValue);
            }
            else
            {
                nError = ERROR_EX_LAYOUT_UNSUPPORTED_PROP;
            }
        }
        else
        {
            nError = ERROR_EX_LAYOUT_UNSUPPORTED_PROP;
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

void _layout_move_margin(HEXOBJ hObj, RECT *lpObjRc, LPVOID lpMargin, INT dwLockFlags, INT dwOrgFlags)
{
    RECT rcObj = *lpObjRc;
    RECT rcMargin{0};
    rcMargin.left = __get(lpMargin, 3 * sizeof(size_t));
    rcMargin.top = __get(lpMargin, 2 * sizeof(size_t));
    rcMargin.right = __get(lpMargin, sizeof(size_t));
    rcMargin.bottom = __get(lpMargin, 0);

    rcObj.left = rcObj.left + rcMargin.left;
    if ((dwLockFlags & 1) == 0)
    {
        rcObj.right = rcObj.right + rcMargin.left;
        lpObjRc->right = lpObjRc->right + rcMargin.left;
    }

    rcObj.top = rcObj.top + rcMargin.top;

    if ((dwLockFlags & 2) == 0)
    {
        rcObj.bottom = rcObj.bottom + rcMargin.top;
        lpObjRc->bottom = lpObjRc->bottom + rcMargin.top;
    }

    if ((dwLockFlags & 4) == 4)
    {
        rcObj.right = rcObj.right - rcMargin.right;
    }
    else
    {
        lpObjRc->right = lpObjRc->right + rcMargin.right;
    }

    if ((dwLockFlags & 8) == 8)
    {
        rcObj.bottom = rcObj.bottom - rcMargin.bottom;
    }
    else
    {
        lpObjRc->bottom = lpObjRc->bottom + rcMargin.bottom;
    }

    if (dwOrgFlags == 15)
    {
        return;
    }

    rcObj.right = rcObj.right - rcObj.left;
    rcObj.bottom = rcObj.bottom - rcObj.top;
    if ((dwOrgFlags & 1) != 0)
    {
        rcObj.left = EOP_DEFAULT;
    }
    if ((dwOrgFlags & 2) != 0)
    {
        rcObj.top = EOP_DEFAULT;
    }
    if ((dwOrgFlags & 4) != 0)
    {
        rcObj.right = EOP_DEFAULT;
    }
    if ((dwOrgFlags & 8) != 0)
    {
        rcObj.bottom = EOP_DEFAULT;
    }

    Ex_ObjMove(hObj, rcObj.left, rcObj.top, rcObj.right, rcObj.bottom, FALSE);
}

LRESULT CALLBACK __layout_linear_proc(layout_s *pLayout, INT nEvent, WPARAM wParam, LPARAM lParam)
{
    if (nEvent == ELN_GETPROPSCOUNT)
    {
        return 2;
    }
    else if (nEvent == ELN_GETCHILDPROPCOUNT)
    {
        return 2;
    }
    else if (nEvent == ELN_INITCHILDPROPS)
    {
        __set((LPVOID)lParam, ELCP_LINEAR_SIZE * sizeof(size_t), -1);
    }
    else if (nEvent == ELN_CHECKCHILDPROPVALUE)
    {
        INT nSize = HIWORD(wParam);
        if (nSize == ELN_CHECKCHILDPROPVALUE)
        {
            return (lParam < ELCP_LINEAR_ALGIN_FILL || lParam > ELCP_LINEAR_ALIGN_RIGHT_BOTTOM);
        }
    }
    else if (nEvent == ELN_UPDATE)
    {
        RECT rcClient{0};
        if (((layout_s *)pLayout)->nBindType_ == HT_OBJECT)
        {
            Ex_ObjGetClientRect(wParam, &rcClient);
        }
        else
        {
            Ex_DUIGetClientRect(wParam, &rcClient);
        }
        LPVOID pInfo = ((layout_s *)pLayout)->lpLayoutInfo_;
        array_s *hArr = ((layout_s *)pLayout)->hArrChildrenInfo_;
        INT nDAlign = __get(pInfo, (ELP_LINEAR_DALIGN - 1) * sizeof(size_t));
        BOOL fVertical = __get(pInfo, (ELP_LINEAR_DIRECTION - 1) * sizeof(size_t)) == ELP_DIRECTION_V;
        rcClient.left = rcClient.left + __get(pInfo, ELP_PADDING_LEFT * sizeof(size_t));
        rcClient.top = rcClient.top + __get(pInfo, ELP_PADDING_TOP * sizeof(size_t));
        rcClient.right = rcClient.right - __get(pInfo, ELP_PADDING_RIGHT * sizeof(size_t));
        rcClient.bottom = rcClient.bottom - __get(pInfo, ELP_PADDING_BOTTOM * sizeof(size_t));
        SIZE szClient;
        szClient.cx = rcClient.right - rcClient.left;
        szClient.cy = rcClient.bottom - rcClient.top;
        RECT rcObj;
        rcObj.left = rcClient.left;
        rcObj.top = rcClient.top;
        std::vector<RECT> arrRect;
        std::vector<INT> arrOrg;
        if (nDAlign != 0 && Array_GetCount(hArr) > 0)
        {
            arrRect.resize(Array_GetCount(hArr));
            arrOrg.resize(Array_GetCount(hArr));
        }
        for (INT i = 1; i <= Array_GetCount(hArr); i++)
        {
            INT orgFlags = 0;
            LPVOID pInfo = (LPVOID)Array_GetMember(hArr, i);
            HEXOBJ hObj = __get(pInfo, 0);
            if (hObj == 0)
                continue;
            INT nSize = __get(pInfo, ELCP_LINEAR_SIZE * sizeof(size_t));
            RECT rcTmp{0};
            Ex_ObjGetRect(hObj, &rcTmp);
            INT w = rcTmp.right - rcTmp.left;
            INT h = rcTmp.bottom - rcTmp.top;
            if (nSize < 0)
            {
                if (fVertical)
                {
                    nSize = h;
                }
                else
                {
                    nSize = w;
                }
            }
            INT nFill = __get(pInfo, ELCP_LINEAR_ALIGN * sizeof(size_t));
            orgFlags = 0;
            if (fVertical)
            {
                if (nFill == ELCP_LINEAR_ALIGN_LEFT_TOP)
                {
                    rcObj.left = rcClient.left;
                    rcObj.right = rcObj.left + w;
                }
                else if (nFill == ELCP_LINEAR_ALIGN_CENTER)
                {
                    rcObj.left = rcClient.left + (szClient.cx - w) / 2;
                    rcObj.right = rcObj.left + w;
                    orgFlags = 4;
                }
                else if (nFill == ELCP_LINEAR_ALIGN_RIGHT_BOTTOM)
                {
                    rcObj.right = rcClient.right;
                    rcObj.left = rcClient.right - w;
                }
                else
                {
                    rcObj.left = rcClient.left;
                    rcObj.right = rcClient.right;
                }
                rcObj.bottom = rcObj.top + nSize;
            }
            else
            {
                if (nFill == ELCP_LINEAR_ALIGN_LEFT_TOP)
                {
                    rcObj.top = rcClient.top;
                    rcObj.bottom = rcObj.top + rcObj.bottom - rcTmp.top;
                }
                else if (nFill == ELCP_LINEAR_ALIGN_CENTER)
                {
                    rcObj.top = rcClient.top + (szClient.cy - h) / 2;
                    rcObj.bottom = rcObj.top + h;
                    orgFlags = 8;
                }
                else if (nFill == ELCP_LINEAR_ALIGN_RIGHT_BOTTOM)
                {
                    rcObj.bottom = rcClient.bottom;
                    rcObj.top = rcClient.bottom - (rcTmp.bottom - rcTmp.top);
                }
                else
                {
                    rcObj.top = rcClient.top;
                    rcObj.bottom = rcClient.bottom;
                }
                rcObj.right = rcObj.left + nSize;
            }
            if (nDAlign == 0)
            {
                _layout_move_margin(hObj, &rcObj, (LPVOID)((size_t)pInfo - 4 * sizeof(size_t)), fVertical ? 5 : 10, orgFlags);
            }
            else
            {
                rcObj.left = rcObj.left + __get(pInfo, ELCP_MARGIN_LEFT * sizeof(size_t));
                rcObj.top = rcObj.top + __get(pInfo, ELCP_MARGIN_TOP * sizeof(size_t));
                rcObj.right = rcObj.right + __get(pInfo, ELCP_MARGIN_RIGHT * sizeof(size_t));
                rcObj.bottom = rcObj.bottom + __get(pInfo, ELCP_MARGIN_BOTTOM * sizeof(size_t));
                arrRect[i - 1] = rcObj;
                arrOrg[i - 1] = orgFlags;
            }
            if (fVertical)
            {
                rcObj.top = rcObj.bottom;
            }
            else
            {
                rcObj.left = rcObj.right;
            }
        }
        if (Array_GetCount(hArr) > 0 && arrRect.size() > 0)
        {
            LPVOID pInfo = ((layout_s *)pLayout)->lpLayoutInfo_;
            INT nDAlign = __get(pInfo, (ELP_LINEAR_DALIGN - 1) * sizeof(size_t));
            INT w = 0;
            INT h = 0;
            if (fVertical)
            {
                INT nSize = arrRect[arrRect.size() - 1].bottom - arrRect[0].top;
                h = 5;
                if (nDAlign == 2) //bottom
                {
                    w = rcClient.bottom - nSize - arrRect[0].top;
                }
                else if (nDAlign == 1) //CENTER
                {
                    w = rcClient.top + (rcClient.bottom - rcClient.top - nSize) / 2 - arrRect[0].top;
                }
                else
                {
                    w = 0;
                }
            }
            else
            {
                INT nSize = arrRect[arrRect.size() - 1].right - arrRect[0].left;
                h = 10;
                if (nDAlign == 2) //right
                {
                    w = rcClient.right - nSize - arrRect[0].left;
                }
                else if (nDAlign == 1) //center
                {
                    w = rcClient.left + (rcClient.right - rcClient.top - nSize) / 2 - arrRect[0].left;
                }
                else
                {
                    w = 0;
                }
            }
            for (INT i = 1; i <= Array_GetCount(hArr); i++)
            {
                LPVOID pInfo = (LPVOID)Array_GetMember(hArr, i);
                RECT rcObj = arrRect[i - 1];
                if (fVertical)
                {
                    OffsetRect(&rcObj, 0, w);
                }
                else
                {
                    OffsetRect(&rcObj, w, 0);
                }
                _layout_move_margin(__get(pInfo, 0), &rcObj, (LPVOID)((size_t)pInfo - 4 * sizeof(size_t)), 15, arrOrg[i - 1]);
            }
        }
    }
    return 0;
}

LRESULT CALLBACK __layout_flow_proc(layout_s *pLayout, INT nEvent, WPARAM wParam, LPARAM lParam)
{
    if (nEvent == ELN_GETPROPSCOUNT)
    {
        return 1;
    }
    else if (nEvent == ELN_GETCHILDPROPCOUNT)
    {
        return 2;
    }
    else if (nEvent == ELN_INITCHILDPROPS)
    {
        __set((LPVOID)lParam, ELCP_FLOW_SIZE * sizeof(size_t), -1);
    }
    else if (nEvent == ELN_UPDATE)
    {
        RECT rcClient{0};
        if (((layout_s *)pLayout)->nBindType_ == HT_OBJECT)
        {
            Ex_ObjGetClientRect(wParam, &rcClient);
        }
        else
        {
            Ex_DUIGetClientRect(wParam, &rcClient);
        }
        LPVOID pInfoa = ((layout_s *)pLayout)->lpLayoutInfo_;
        array_s *hArr = ((layout_s *)pLayout)->hArrChildrenInfo_;
        BOOL fVertical = __get(pInfoa, (ELP_LINEAR_DIRECTION - 1) * sizeof(size_t)) == ELP_DIRECTION_V;
        rcClient.left = rcClient.left + __get(pInfoa, ELP_PADDING_LEFT * sizeof(size_t));
        rcClient.top = rcClient.top + __get(pInfoa, ELP_PADDING_TOP * sizeof(size_t));
        rcClient.right = rcClient.right - __get(pInfoa, ELP_PADDING_RIGHT * sizeof(size_t));
        rcClient.bottom = rcClient.bottom - __get(pInfoa, ELP_PADDING_BOTTOM * sizeof(size_t));
        RECT rcObj{0};
        rcObj.left = rcClient.left;
        rcObj.top = rcClient.top;

        INT nMaxSize = 0;
        for (INT i = 1; i <= Array_GetCount(hArr); i++)
        {
            LPVOID pInfo = (LPVOID)Array_GetMember(hArr, i);
            HEXOBJ hObj = (HEXOBJ)__get(pInfo, 0);
            if (hObj == 0 || !Ex_ObjIsVisible(hObj))
                continue;
            INT nSize = __get(pInfo, ELCP_LINEAR_SIZE * sizeof(size_t));
            RECT rcTmp{0};
            Ex_ObjGetRect(hObj, &rcTmp);
            if (nSize < 0)
            {
                if (fVertical)
                {
                    nSize = rcTmp.bottom - rcTmp.top;
                }
                else
                {
                    nSize = rcTmp.right - rcTmp.left;
                }
            }
            if (fVertical)
            {
                rcObj.right = rcObj.left + rcTmp.right - rcTmp.left;
                rcObj.bottom = rcObj.top + nSize;
                if (rcObj.bottom > rcClient.bottom || __get(pInfo, ELCP_FLOW_NEW_LINE * sizeof(size_t)) != 0)
                {
                    rcObj.top = rcClient.top;
                    rcObj.bottom = rcObj.top + nSize;
                    rcObj.left = rcObj.left + nMaxSize;
                    rcObj.right = rcObj.left + rcTmp.right - rcTmp.left;
                    nMaxSize = 0;
                }
            }
            else
            {
                rcObj.bottom = rcObj.top + rcTmp.bottom - rcTmp.top;
                rcObj.right = rcObj.left + nSize;
                if (rcObj.right > rcClient.right || __get(pInfo, ELCP_FLOW_NEW_LINE * sizeof(size_t)) != 0)
                {
                    rcObj.left = rcClient.left;
                    rcObj.right = rcObj.left + nSize;
                    rcObj.top = rcObj.top + nMaxSize;
                    rcObj.bottom = rcObj.top + rcTmp.bottom - rcTmp.top;
                    nMaxSize = 0;
                }
            }
            _layout_move_margin(hObj, &rcObj, (LPVOID)((size_t)pInfo - 4 * sizeof(size_t)), 0, 0);
            if (fVertical)
            {
                if (rcObj.right - rcObj.left > nMaxSize)
                {
                    nMaxSize = rcObj.right - rcObj.left;
                }
                rcObj.top = rcObj.bottom;
            }
            else
            {
                if (rcObj.bottom - rcObj.top > nMaxSize)
                {
                    nMaxSize = rcObj.bottom - rcObj.top;
                }
                rcObj.left = rcObj.right;
            }
        }
    }
    return 0;
}

LRESULT CALLBACK __layout_page_proc(layout_s *pLayout, INT nEvent, WPARAM wParam, LPARAM lParam)
{
    if (nEvent == ELN_GETPROPSCOUNT)
    {
        return 1;
    }
    else if (nEvent == ELN_GETCHILDPROPCOUNT)
    {
        return 1;
    }
    else if (nEvent == ELN_UPDATE)
    {
        RECT rcClient{0};
        if (((layout_s *)pLayout)->nBindType_ == HT_OBJECT)
        {
            Ex_ObjGetClientRect(wParam, &rcClient);
        }
        else
        {
            Ex_DUIGetClientRect(wParam, &rcClient);
        }
        LPVOID pInfoa = ((layout_s *)pLayout)->lpLayoutInfo_;
        array_s *hArr = ((layout_s *)pLayout)->hArrChildrenInfo_;
        BOOL fVertical = __get(pInfoa, (ELP_LINEAR_DIRECTION - 1) * sizeof(size_t)) == ELP_DIRECTION_V;
        rcClient.left = rcClient.left + __get(pInfoa, ELP_PADDING_LEFT * sizeof(size_t));
        rcClient.top = rcClient.top + __get(pInfoa, ELP_PADDING_TOP * sizeof(size_t));
        rcClient.right = rcClient.right - __get(pInfoa, ELP_PADDING_RIGHT * sizeof(size_t));
        rcClient.bottom = rcClient.bottom - __get(pInfoa, ELP_PADDING_BOTTOM * sizeof(size_t));
        INT nCurrentPage = __get(pInfoa, (ELP_PAGE_CURRENT - 1) * sizeof(size_t));
        for (INT i = 1; i <= Array_GetCount(hArr); i++)
        {
            LPVOID pInfo = (LPVOID)Array_GetMember(hArr, i);
            HEXOBJ hObj = (HEXOBJ)__get(pInfo, 0);
            if (hObj == 0)
                continue;
            if (i == nCurrentPage)
            {
                if (__get(pInfo, ELCP_PAGE_FILL * sizeof(size_t)) != 0)
                {
                    _layout_move_margin(hObj, &rcClient, (LPVOID)((size_t)pInfo - 4 * sizeof(size_t)), 15, 0);
                }
            }
            Ex_ObjShow(hObj, i == nCurrentPage);
        }
    }
    return 0;
}

LRESULT CALLBACK __layout_table_proc(layout_s *pLayout, INT nEvent, WPARAM wParam, LPARAM lParam)
{
    if (nEvent == ELN_GETPROPSCOUNT)
    {
        //' layout_rows = 行数 = 类似 "100,200,50"
        //' layout_cells = 列数 = 类似 "100,200,50"
        //' LAYOUT_ROW_ARRAY = 正数为像素,负数为百分比
        //' LAYOUT_CELL_ARRAY
        return 2;
    }
    else if (nEvent == ELN_GETCHILDPROPCOUNT)
    {
        /*' layout_row = 行号
		' layout_cell = 列号
		' layout_rowspan = 跨行数
		' layout_cellspan = 跨列数
		' layout_fill = 是否填充,否则放左上角*/
        return 5;
    }
    else if (nEvent == ELN_INITPROPS)
    {
        __set((LPVOID)lParam, (ELP_TABLE_ARRAY_ROW - 1) * sizeof(size_t), (size_t)Array_Create(0));
        __set((LPVOID)lParam, (ELP_TABLE_ARRAY_CELL - 1) * sizeof(size_t), (size_t)Array_Create(0));
    }
    else if (nEvent == ELN_INITCHILDPROPS)
    {
        __set((LPVOID)lParam, ELCP_TABLE_ROW_SPAN * sizeof(size_t), 1);
        __set((LPVOID)lParam, ELCP_TABLE_CELL_SPAN * sizeof(size_t), 1);
    }
    else if (nEvent == ELN_UNINITPROPS)
    {
        Array_Destroy((array_s *)__get((LPVOID)lParam, (ELP_TABLE_ARRAY_ROW - 1) * sizeof(size_t)));
        Array_Destroy((array_s *)__get((LPVOID)lParam, (ELP_TABLE_ARRAY_CELL - 1) * sizeof(size_t)));
    }
    else if (nEvent == ELN_UPDATE)
    {
        RECT rcClient{0};
        if (((layout_s *)pLayout)->nBindType_ == HT_OBJECT)
        {
            Ex_ObjGetClientRect(wParam, &rcClient);
        }
        else
        {
            Ex_DUIGetClientRect(wParam, &rcClient);
        }
        LPVOID pInfoa = ((layout_s *)pLayout)->lpLayoutInfo_;
        array_s *hArr = ((layout_s *)pLayout)->hArrChildrenInfo_;
        array_s *hArrRows = (array_s *)__get(pInfoa, (ELP_TABLE_ARRAY_ROW - 1) * sizeof(size_t));
        array_s *hArrCells = (array_s *)__get(pInfoa, (ELP_TABLE_ARRAY_CELL - 1) * sizeof(size_t));

        rcClient.left = rcClient.left + __get(pInfoa, ELP_PADDING_LEFT * sizeof(size_t));
        rcClient.top = rcClient.top + __get(pInfoa, ELP_PADDING_TOP * sizeof(size_t));
        rcClient.right = rcClient.right - __get(pInfoa, ELP_PADDING_RIGHT * sizeof(size_t));
        rcClient.bottom = rcClient.bottom - __get(pInfoa, ELP_PADDING_BOTTOM * sizeof(size_t));
        std::vector<std::vector<RECT>> aRects;
        RECT rcTmp{0};
        if (Array_GetCount(hArrRows) > 0 && Array_GetCount(hArrCells) > 0)
        {
            aRects.resize(Array_GetCount(hArrRows));
            for (INT index = 0; index < aRects.size(); index++)
            {
                aRects[index].resize(Array_GetCount(hArrCells));
            }
            rcTmp.top = rcClient.top;
            for (INT i = 1; i <= Array_GetCount(hArrRows); i++)
            {
                rcTmp.left = rcClient.left;
                rcTmp.bottom = Array_GetMember(hArrRows, i);
                if (rcTmp.bottom < 0)
                {
                    rcTmp.bottom = (rcClient.bottom - rcClient.top) * (FLOAT)abs(rcTmp.bottom) / 100;
                }
                for (INT j = 1; j <= Array_GetCount(hArrCells); j++)
                {
                    aRects[i - 1][j - 1].left = rcTmp.left;
                    aRects[i - 1][j - 1].top = rcTmp.top;
                    rcTmp.right = Array_GetMember(hArrCells, j);
                    if (rcTmp.right < 0)
                    {
                        rcTmp.right = (rcClient.right - rcClient.left) * (FLOAT)abs(rcTmp.right) / 100;
                    }
                    aRects[i - 1][j - 1].right = aRects[i - 1][j - 1].left + rcTmp.right;
                    aRects[i - 1][j - 1].bottom = aRects[i - 1][j - 1].top + rcTmp.bottom;
                    rcTmp.left = rcTmp.left + rcTmp.right;
                }
                rcTmp.top = rcTmp.top + rcTmp.bottom;
            }
        }
        else
        {
            Ex_SetLastError(ERROR_EX_LAYOUT_INVALID);
            return -1;
        }
        for (INT i = 1; i <= Array_GetCount(hArr); i++)
        {
            LPVOID pInfo = (LPVOID)Array_GetMember(hArr, i);
            HEXOBJ hObj = __get(pInfo, 0);
            if (hObj == 0)
                continue;
            rcTmp.left = __get(pInfo, ELCP_TABLE_CELL * sizeof(size_t));
            rcTmp.top = __get(pInfo, ELCP_TABLE_ROW * sizeof(size_t));
            rcTmp.right = __get(pInfo, ELCP_TABLE_CELL_SPAN * sizeof(size_t)) - 1;
            if (rcTmp.right <= 0)
            {
                rcTmp.right = rcTmp.left;
            }
            else
            {
                rcTmp.right = rcTmp.left + rcTmp.right;
            }
            rcTmp.bottom = __get(pInfo, ELCP_TABLE_ROW_SPAN * sizeof(size_t)) - 1;
            if (rcTmp.bottom <= 0)
            {
                rcTmp.bottom = rcTmp.top;
            }
            else
            {
                rcTmp.bottom = rcTmp.top + rcTmp.bottom;
            }
            if (rcTmp.left <= 0)
            {
                rcTmp.left = 1;
            }
            if (rcTmp.top <= 0)
            {
                rcTmp.top = 1;
            }
            if (rcTmp.left > Array_GetCount(hArrCells))
            {
                rcTmp.left = Array_GetCount(hArrCells);
            }
            if (rcTmp.top > Array_GetCount(hArrRows))
            {
                rcTmp.top = Array_GetCount(hArrRows);
            }
            if (rcTmp.right < rcTmp.left)
            {
                rcTmp.right = rcTmp.left;
            }
            if (rcTmp.bottom < rcTmp.top)
            {
                rcTmp.bottom = rcTmp.top;
            }
            if (rcTmp.right > Array_GetCount(hArrCells))
            {
                rcTmp.right = Array_GetCount(hArrCells);
            }
            if (rcTmp.bottom > Array_GetCount(hArrRows))
            {
                rcTmp.bottom = Array_GetCount(hArrRows);
            }
            rcClient.left = aRects[rcTmp.top - 1][rcTmp.left - 1].left;
            rcClient.top = aRects[rcTmp.top - 1][rcTmp.left - 1].top;
            rcClient.right = aRects[rcTmp.bottom - 1][rcTmp.right - 1].right;
            rcClient.bottom = aRects[rcTmp.bottom - 1][rcTmp.right - 1].bottom;
            _layout_move_margin(hObj, &rcClient, (LPVOID)((size_t)pInfo - 4 * sizeof(size_t)), 15, 0);
        }
    }
    return 0;
}

LRESULT CALLBACK __layout_relative_proc(layout_s *pLayout, INT nEvent, WPARAM wParam, LPARAM lParam)
{
    if (nEvent == ELN_GETPROPSCOUNT)
    {
        return 0;
    }
    else if (nEvent == ELN_GETCHILDPROPCOUNT)
    {
        return 10;
    }
    else if (nEvent == ELN_CHECKCHILDPROPVALUE)
    {
        if (Ex_ObjIsValidate(lParam) && LOWORD(wParam) > 0)
        {
            array_s *pChildrenInfo = ((layout_s *)pLayout)->hArrChildrenInfo_;
            LPVOID pInfo = (LPVOID)Array_GetMember(pChildrenInfo, LOWORD(wParam));
            HEXOBJ hObj = __get(pInfo, 0);
            INT dwPropID = HIWORD(wParam);
            LPVOID pInfoOther = _layout_get_child((layout_s *)pLayout, lParam);
            BOOL nRet = FALSE;

            if (hObj != 0 && dwPropID > 0 && pInfoOther != 0)
            {
                if (dwPropID == ELCP_RELATIVE_LEFT_OF)
                {
                    nRet = __get(pInfoOther, ELCP_RELATIVE_RIGHT_OF * sizeof(size_t)) != hObj;
                }
                else if (dwPropID == ELCP_RELATIVE_RIGHT_OF)
                {
                    nRet = __get(pInfoOther, ELCP_RELATIVE_LEFT_OF * sizeof(size_t)) != hObj;
                }
                else if (dwPropID == ELCP_RELATIVE_TOP_OF)
                {
                    nRet = __get(pInfoOther, ELCP_RELATIVE_BOTTOM_OF * sizeof(size_t)) != hObj;
                }
                else if (dwPropID == ELCP_RELATIVE_BOTTOM_OF)
                {
                    nRet = __get(pInfoOther, ELCP_RELATIVE_TOP_OF * sizeof(size_t)) != hObj;
                }
                else
                {

                    nRet = __get(pInfoOther, dwPropID * sizeof(size_t)) != hObj;
                }
            }
            return nRet == TRUE ? FALSE : TRUE;
        }
    }
    else if (nEvent == ELN_UPDATE)
    {
        _layout_relative_update((layout_s *)pLayout, ((layout_s *)pLayout)->lpLayoutInfo_, ((layout_s *)pLayout)->hArrChildrenInfo_, lParam);
    }
    return 0;
}

void _layout_relative_update(layout_s *pLayout, LPVOID pLayoutInfo, array_s *hArrObjs, LPARAM lParam)
{
    INT Prime = GetNearestPrime(Array_GetCount(hArrObjs));
    EX_HASHTABLE *hHashPosInfos = HashTable_Create(Prime, pfnDefaultFreeData);
    EXHANDLE hObjParent = ((layout_s *)pLayout)->hBind_;
    RECT rcClient{0};
    if (((layout_s *)pLayout)->nBindType_ == HT_OBJECT)
    {
        Ex_ObjGetClientRect(hObjParent, &rcClient);
    }
    else
    {
        Ex_DUIGetClientRect(hObjParent, &rcClient);
    }
    rcClient.left = rcClient.left + __get(pLayoutInfo, ELP_PADDING_LEFT * sizeof(size_t));
    rcClient.top = rcClient.top + __get(pLayoutInfo, ELP_PADDING_TOP * sizeof(size_t));
    rcClient.right = rcClient.right - __get(pLayoutInfo, ELP_PADDING_RIGHT * sizeof(size_t));
    rcClient.bottom = rcClient.bottom - __get(pLayoutInfo, ELP_PADDING_BOTTOM * sizeof(size_t));
    std::vector<INT> Infos(3);
    for (INT i = 1; i <= Array_GetCount(hArrObjs); i++)
    {
        LPVOID pInfo = (LPVOID)Array_GetMember(hArrObjs, i);
        HEXOBJ hObj = (HEXOBJ)__get(pInfo, 0);
        if (hObj == 0)
            continue;
        RECT rcObj{0};
        Ex_ObjGetRect(hObj, &rcObj);

        LPVOID pPosInfo = Ex_MemAlloc(4 * 3 * sizeof(size_t) + sizeof(size_t) + sizeof(size_t)); //多一个放pInfo和orgFlags
        //[是否确定/类型/句柄或坐标]*4个边界,确定以后一定是坐标
        //处理无法确定四边的情况
        BOOL fNoPosInfoH = TRUE;
        for (INT j = 1; j <= 10; j += 2)
        {
            if (__get(pInfo, j * sizeof(size_t)) != 0)
            {
                fNoPosInfoH = FALSE;
                break;
            }
        }
        BOOL fNoPosInfoV = TRUE;
        for (INT j = 2; j <= 10; j += 2)
        {
            if (__get(pInfo, j * sizeof(size_t)) != 0)
            {
                fNoPosInfoV = FALSE;
                break;
            }
        }

        if (fNoPosInfoH)
        {
            __set(pPosInfo, 0, 1);
            __set(pPosInfo, sizeof(size_t), 0);
            __set(pPosInfo, 2 * sizeof(size_t), rcObj.left + __get(pInfo, ELCP_MARGIN_LEFT * sizeof(size_t)));
            __set((LPVOID)((size_t)pPosInfo + 6 * sizeof(size_t)), 0, 1);
            __set((LPVOID)((size_t)pPosInfo + 6 * sizeof(size_t)), sizeof(size_t), 0);
            __set((LPVOID)((size_t)pPosInfo + 6 * sizeof(size_t)), 2 * sizeof(size_t), rcObj.right + __get(pInfo, ELCP_MARGIN_LEFT * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_RIGHT * sizeof(size_t)));
        }
        if (fNoPosInfoV)
        {

            __set((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t)), 0, 1);
            __set((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t)), sizeof(size_t), 0);
            __set((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t)), 2 * sizeof(size_t), rcObj.top + __get(pInfo, ELCP_MARGIN_TOP * sizeof(size_t)));

            __set((LPVOID)((size_t)pPosInfo + 9 * sizeof(size_t)), 0, 1);
            __set((LPVOID)((size_t)pPosInfo + 9 * sizeof(size_t)), sizeof(size_t), 0);
            __set((LPVOID)((size_t)pPosInfo + 9 * sizeof(size_t)), 2 * sizeof(size_t), rcObj.bottom + __get(pInfo, ELCP_MARGIN_TOP * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_BOTTOM * sizeof(size_t)));
        }
        //rcObj暂时按左顶宽高处理
        rcObj.right = rcObj.right - rcObj.left;
        rcObj.bottom = rcObj.bottom - rcObj.top;
        INT orgFlags = 0;
        //预处理边界定位信息

        HEXDUI hExDUI = 0;
        if (fNoPosInfoH == FALSE)
        { //左边界处理
            Infos[0] = 1;
            if (__get(pInfo, ELCP_RELATIVE_LEFT_ALIGN_OF * sizeof(size_t)) != 0)
            {
                INT dwValue = __get(pInfo, ELCP_RELATIVE_LEFT_ALIGN_OF * sizeof(size_t));
                Infos[1] = ELCP_RELATIVE_LEFT_ALIGN_OF;
                HEXDUI hExDUI = 0;
                if (dwValue == -1) //相对父
                {
                    Infos[2] = rcClient.left + __get(pInfo, ELCP_MARGIN_LEFT * sizeof(size_t));
                }
                else if (dwValue != 0 && (hObjParent == Ex_ObjGetParentEx(dwValue, &hExDUI)) || hObjParent == hExDUI) //同层组件
                {
                    Infos[0] = 0;
                    Infos[2] = dwValue;
                }
                else
                {
                    Infos[0] = 0;
                    Infos[1] = 0;
                    Infos[2] = rcObj.right;
                }
            }
            else if (__get(pInfo, ELCP_RELATIVE_CENTER_PARENT_H * sizeof(size_t)) != 0)
            {
                Infos[1] = ELCP_RELATIVE_CENTER_PARENT_H;
                Infos[2] = rcClient.left + abs(rcClient.right - rcClient.left - rcObj.right) / 2 + __get(pInfo, ELCP_MARGIN_LEFT * sizeof(size_t));
                orgFlags = orgFlags | 4;
            }
            else
            {
                INT dwValue = __get(pInfo, ELCP_RELATIVE_RIGHT_OF * sizeof(size_t));
                HEXDUI hExDUI = 0;
                if (dwValue != 0 && (hObjParent == Ex_ObjGetParentEx(dwValue, &hExDUI)) || hObjParent == hExDUI) //同层组件
                {
                    Infos[0] = 0;
                    Infos[1] = ELCP_RELATIVE_RIGHT_OF;
                    Infos[2] = dwValue;
                }
                else
                {
                    Infos[0] = 0;
                    Infos[1] = 0;
                    Infos[2] = rcObj.right;
                }
            }
            __set(pPosInfo, 0, Infos[0]);
            __set(pPosInfo, sizeof(size_t), Infos[1]);
            __set(pPosInfo, 2 * sizeof(size_t), Infos[2]);
            //右边界处理
            Infos[0] = 1;

            if (__get(pInfo, ELCP_RELATIVE_RIGHT_ALIGN_OF * sizeof(size_t)) != 0)
            {
                INT dwValue = __get(pInfo, ELCP_RELATIVE_RIGHT_ALIGN_OF * sizeof(size_t));
                Infos[1] = ELCP_RELATIVE_RIGHT_ALIGN_OF;
                HEXDUI hExDUI = 0;
                if (dwValue == -1) //相对父
                {
                    Infos[2] = rcClient.right + __get(pInfo, ELCP_MARGIN_LEFT * sizeof(size_t));
                }
                else if (dwValue != 0 && (hObjParent == Ex_ObjGetParentEx(dwValue, &hExDUI)) || hObjParent == hExDUI) //同层组件
                {
                    Infos[0] = 0;
                    Infos[2] = dwValue;
                }
                else
                {
                    Infos[0] = 0;
                    Infos[1] = 0;
                    Infos[2] = rcObj.right;
                }
            }
            else if (__get(pInfo, ELCP_RELATIVE_CENTER_PARENT_H * sizeof(size_t)) != 0)
            {
                Infos[1] = ELCP_RELATIVE_CENTER_PARENT_H;
                Infos[2] = rcClient.left + abs(rcClient.right - rcClient.left + rcObj.right) / 2 + __get(pInfo, ELCP_MARGIN_LEFT * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_RIGHT * sizeof(size_t));
                orgFlags = orgFlags | 4;
            }
            else
            {
                INT dwValue = __get(pInfo, ELCP_RELATIVE_LEFT_OF * sizeof(size_t));
                HEXDUI hExDUI = 0;
                if (dwValue != 0 && (hObjParent == Ex_ObjGetParentEx(dwValue, &hExDUI)) || hObjParent == hExDUI) //同层组件
                {
                    Infos[0] = 0;
                    Infos[1] = ELCP_RELATIVE_LEFT_OF;
                    Infos[2] = dwValue;
                }
                else
                {
                    Infos[0] = 0;
                    Infos[1] = 0;
                    Infos[2] = rcObj.right;
                }
            }
            __set((LPVOID)((size_t)pPosInfo + 2 * 3 * sizeof(size_t)), 0, Infos[0]);
            __set((LPVOID)((size_t)pPosInfo + 2 * 3 * sizeof(size_t)), sizeof(size_t), Infos[1]);
            __set((LPVOID)((size_t)pPosInfo + 2 * 3 * sizeof(size_t)), 2 * sizeof(size_t), Infos[2]);
        }
        if (fNoPosInfoV == FALSE)
        {
            //上边界处理
            Infos[0] = 1;
            if (__get(pInfo, ELCP_RELATIVE_TOP_ALIGN_OF * sizeof(size_t)) != 0)
            {
                INT dwValue = __get(pInfo, ELCP_RELATIVE_TOP_ALIGN_OF * sizeof(size_t));
                Infos[1] = ELCP_RELATIVE_TOP_ALIGN_OF;
                HEXDUI hExDUI = 0;
                if (dwValue == -1) //相对父
                {
                    Infos[2] = rcClient.top;
                }
                else if (dwValue != 0 && (hObjParent == Ex_ObjGetParentEx(dwValue, &hExDUI)) || hObjParent == hExDUI) //同层组件
                {
                    Infos[0] = 0;
                    Infos[2] = dwValue;
                }
                else
                {
                    Infos[0] = 0;
                    Infos[1] = 0;
                    Infos[2] = rcObj.bottom;
                }
            }
            else if (__get(pInfo, ELCP_RELATIVE_CENTER_PARENT_V * sizeof(size_t)) != 0)
            {
                Infos[1] = ELCP_RELATIVE_CENTER_PARENT_V;
                Infos[2] = rcClient.top + abs(rcClient.bottom - rcClient.top - rcObj.bottom) / 2 + __get(pInfo, ELCP_MARGIN_TOP * sizeof(size_t));
                orgFlags = orgFlags | 8;
            }
            else
            {
                INT dwValue = __get(pInfo, ELCP_RELATIVE_BOTTOM_OF * sizeof(size_t));
                HEXDUI hExDUI = 0;
                if (dwValue != 0 && (hObjParent == Ex_ObjGetParentEx(dwValue, &hExDUI)) || hObjParent == hExDUI) //同层组件
                {

                    Infos[0] = 0;
                    Infos[1] = ELCP_RELATIVE_BOTTOM_OF;
                    Infos[2] = dwValue;
                }
                else
                {
                    Infos[0] = 0;
                    Infos[1] = 0;
                    Infos[2] = rcObj.bottom;
                }
            }
            __set((LPVOID)((size_t)pPosInfo + 1 * 3 * sizeof(size_t)), 0, Infos[0]);
            __set((LPVOID)((size_t)pPosInfo + 1 * 3 * sizeof(size_t)), sizeof(size_t), Infos[1]);
            __set((LPVOID)((size_t)pPosInfo + 1 * 3 * sizeof(size_t)), 2 * sizeof(size_t), Infos[2]);

            //下边界处理
            Infos[0] = 1;
            if (__get(pInfo, ELCP_RELATIVE_BOTTOM_ALIGN_OF * sizeof(size_t)) != 0)
            {
                INT dwValue = __get(pInfo, ELCP_RELATIVE_BOTTOM_ALIGN_OF * sizeof(size_t));
                Infos[1] = ELCP_RELATIVE_BOTTOM_ALIGN_OF;
                HEXDUI hExDUI = 0;
                if (dwValue == -1) //相对父
                {
                    Infos[2] = rcClient.bottom + __get(pInfo, ELCP_MARGIN_TOP * sizeof(size_t)) - __get(pInfo, ELCP_MARGIN_BOTTOM * sizeof(size_t));
                }
                else if (dwValue != 0 && (hObjParent == Ex_ObjGetParentEx(dwValue, &hExDUI)) || hObjParent == hExDUI) //同层组件
                {
                    Infos[0] = 0;
                    Infos[2] = dwValue;
                }
                else
                {
                    Infos[0] = 0;
                    Infos[1] = 0;
                    Infos[2] = rcObj.bottom;
                }
            }
            else if (__get(pInfo, ELCP_RELATIVE_CENTER_PARENT_V * sizeof(size_t)) != 0)
            {
                Infos[1] = ELCP_RELATIVE_CENTER_PARENT_V;
                Infos[2] = rcClient.top + abs(rcClient.bottom - rcClient.top + rcObj.bottom) / 2 + __get(pInfo, ELCP_MARGIN_TOP * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_BOTTOM * sizeof(size_t));
                orgFlags = orgFlags | 8;
            }
            else
            {
                INT dwValue = __get(pInfo, ELCP_RELATIVE_TOP_OF * sizeof(size_t));
                HEXDUI hExDUI = 0;
                if (dwValue != 0 && (hObjParent == Ex_ObjGetParentEx(dwValue, &hExDUI)) || hObjParent == hExDUI) //同层组件
                {
                    Infos[0] = 0;
                    Infos[1] = ELCP_RELATIVE_TOP_OF;
                    Infos[2] = dwValue;
                }
                else
                {
                    Infos[0] = 0;
                    Infos[1] = 0;
                    Infos[2] = rcObj.bottom;
                }
            }
            __set((LPVOID)((size_t)pPosInfo + 3 * 3 * sizeof(size_t)), 0, Infos[0]);
            __set((LPVOID)((size_t)pPosInfo + 3 * 3 * sizeof(size_t)), sizeof(size_t), Infos[1]);
            __set((LPVOID)((size_t)pPosInfo + 3 * 3 * sizeof(size_t)), 2 * sizeof(size_t), Infos[2]);
        }
        __set(pPosInfo, 12 * sizeof(size_t), (size_t)pInfo);
        __set(pPosInfo, 12 * sizeof(size_t) + sizeof(size_t), orgFlags);
        HashTable_Set(hHashPosInfos, hObj, (size_t)pPosInfo);
    }

    for (INT index = 0; index < 5; index++)
    {
        INT cNoLockObj = HashTable_GetCounts(hHashPosInfos);
        for (INT i = 1; i <= Array_GetCount(hArrObjs); i++)
        {
            LPVOID pInfo = (LPVOID)Array_GetMember(hArrObjs, i);
            HEXOBJ hObj = __get(pInfo, 0);
            LPVOID pPosInfo = nullptr;
            HashTable_Get(hHashPosInfos, hObj, (size_t *)&pPosInfo);
            if (pPosInfo != 0)
            {
                //找能确定的点
                if (__get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t) * 0), 0) == 0)
                {
                    Infos[0] = __get(pPosInfo, 0);
                    Infos[1] = __get(pPosInfo, sizeof(size_t));
                    Infos[2] = __get(pPosInfo, 2 * sizeof(size_t));

                    if (Infos[1] == ELCP_RELATIVE_RIGHT_OF)
                    {
                        LPVOID pInfoOther = nullptr;
                        if (HashTable_Get(hHashPosInfos, Infos[2], (size_t *)&pInfoOther))
                        {
                            if (__get(pInfoOther, 2 * 3 * sizeof(size_t)) != 0) //已经锁定了
                            {
                                Infos[2] = __get(pInfoOther, 2 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_LEFT * sizeof(size_t));
                                Infos[0] = 1;
                            }
                        }
                    }
                    else if (Infos[1] == ELCP_RELATIVE_LEFT_ALIGN_OF)
                    {
                        LPVOID pInfoOther = nullptr;
                        if (HashTable_Get(hHashPosInfos, Infos[2], (size_t *)&pInfoOther))
                        {
                            if (__get(pInfoOther, 0 * 3 * sizeof(size_t)) != 0) //已经锁定了
                            {
                                Infos[2] = __get(pInfoOther, 0 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_LEFT * sizeof(size_t));
                                Infos[0] = 1;
                            }
                        }
                    }
                    else if (Infos[1] == 0)
                    {
                        if (__get(pPosInfo, 2 * 3 * sizeof(size_t)) != 0) //已经锁定了
                        {
                            Infos[2] = __get(pPosInfo, 2 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) - Infos[2] - __get(pInfo, ELCP_MARGIN_RIGHT * sizeof(size_t)) - __get(pInfo, ELCP_MARGIN_LEFT * sizeof(size_t));
                            Infos[0] = 1;
                        }
                    }
                    __set(pPosInfo, 0, Infos[0]);
                    __set(pPosInfo, sizeof(size_t), Infos[1]);
                    __set(pPosInfo, 2 * sizeof(size_t), Infos[2]);
                }
                if (__get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t) * 1), 0) == 0)
                {
                    Infos[0] = __get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t)), 0);
                    Infos[1] = __get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t)), sizeof(size_t));
                    Infos[2] = __get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t)), 2 * sizeof(size_t));

                    if (Infos[1] == ELCP_RELATIVE_BOTTOM_OF)
                    {
                        LPVOID pInfoOther = nullptr;
                        if (HashTable_Get(hHashPosInfos, Infos[2], (size_t *)&pInfoOther))
                        {
                            if (__get(pInfoOther, 3 * 3 * sizeof(size_t)) != 0) //已经锁定了
                            {
                                Infos[2] = __get(pInfoOther, 3 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_TOP * sizeof(size_t));
                                Infos[0] = 1;
                            }
                        }
                    }
                    else if (Infos[1] == ELCP_RELATIVE_TOP_ALIGN_OF)
                    {
                        LPVOID pInfoOther = nullptr;
                        if (HashTable_Get(hHashPosInfos, Infos[2], (size_t *)&pInfoOther))
                        {
                            if (__get(pInfoOther, 1 * 3 * sizeof(size_t)) != 0) //已经锁定了
                            {
                                Infos[2] = __get(pInfoOther, 1 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_TOP * sizeof(size_t));
                                Infos[0] = 1;
                            }
                        }
                    }
                    else if (Infos[1] == 0)
                    {
                        if (__get(pPosInfo, 3 * 3 * sizeof(size_t)) != 0) //已经锁定了
                        {
                            Infos[2] = __get(pPosInfo, 3 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) - Infos[2] - __get(pInfo, ELCP_MARGIN_BOTTOM * sizeof(size_t)) - __get(pInfo, ELCP_MARGIN_TOP * sizeof(size_t));
                            Infos[0] = 1;
                        }
                    }
                    __set((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t)), 0, Infos[0]);
                    __set((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t)), sizeof(size_t), Infos[1]);
                    __set((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t)), 2 * sizeof(size_t), Infos[2]);
                }
                if (__get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t) * 2), 0) == 0)
                {
                    Infos[0] = __get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t) * 2), 0);
                    Infos[1] = __get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t) * 2), sizeof(size_t));
                    Infos[2] = __get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t) * 2), 2 * sizeof(size_t));

                    if (Infos[1] == ELCP_RELATIVE_LEFT_OF)
                    {
                        LPVOID pInfoOther = nullptr;
                        if (HashTable_Get(hHashPosInfos, Infos[2], (size_t *)&pInfoOther))
                        {
                            if (__get(pInfoOther, 0 * 3 * sizeof(size_t)) != 0) //已经锁定了
                            {
                                Infos[2] = __get(pInfoOther, 0 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_RIGHT * sizeof(size_t));
                                Infos[0] = 1;
                            }
                        }
                    }
                    else if (Infos[1] == ELCP_RELATIVE_RIGHT_ALIGN_OF)
                    {

                        LPVOID pInfoOther = nullptr;
                        if (HashTable_Get(hHashPosInfos, Infos[2], (size_t *)&pInfoOther))
                        {
                            if (__get(pInfoOther, 2 * 3 * sizeof(size_t)) != 0) //已经锁定了
                            {
                                Infos[2] = __get(pInfoOther, 2 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_RIGHT * sizeof(size_t));
                                Infos[0] = 1;
                            }
                        }
                    }
                    else if (Infos[1] == 0)
                    {
                        if (__get(pPosInfo, 0 * 3 * sizeof(size_t)) != 0) //已经锁定了
                        {
                            Infos[2] = __get(pPosInfo, 0 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) + Infos[2] + __get(pInfo, ELCP_MARGIN_LEFT * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_RIGHT * sizeof(size_t));
                            Infos[0] = 1;
                        }
                    }
                    __set((LPVOID)((size_t)pPosInfo + 2 * 3 * sizeof(size_t)), 0, Infos[0]);
                    __set((LPVOID)((size_t)pPosInfo + 2 * 3 * sizeof(size_t)), sizeof(size_t), Infos[1]);
                    __set((LPVOID)((size_t)pPosInfo + 2 * 3 * sizeof(size_t)), 2 * sizeof(size_t), Infos[2]);
                }
                if (__get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t) * 3), 0) == 0)
                {
                    Infos[0] = __get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t) * 3), 0);
                    Infos[1] = __get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t) * 3), sizeof(size_t));
                    Infos[2] = __get((LPVOID)((size_t)pPosInfo + 3 * sizeof(size_t) * 3), 2 * sizeof(size_t));

                    if (Infos[1] == ELCP_RELATIVE_TOP_OF)
                    {
                        LPVOID pInfoOther = nullptr;
                        if (HashTable_Get(hHashPosInfos, Infos[2], (size_t *)&pInfoOther))
                        {
                            if (__get(pInfoOther, 1 * 3 * sizeof(size_t)) != 0) //已经锁定了
                            {
                                Infos[2] = __get(pInfoOther, 1 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_BOTTOM * sizeof(size_t));
                                Infos[0] = 1;
                            }
                        }
                    }
                    else if (Infos[1] == ELCP_RELATIVE_BOTTOM_ALIGN_OF)
                    {
                        LPVOID pInfoOther = nullptr;
                        if (HashTable_Get(hHashPosInfos, Infos[2], (size_t *)&pInfoOther))
                        {
                            if (__get(pInfoOther, 3 * 3 * sizeof(size_t)) != 0) //已经锁定了
                            {
                                Infos[2] = __get(pInfoOther, 3 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_BOTTOM * sizeof(size_t));
                                Infos[0] = 1;
                            }
                        }
                    }
                    else if (Infos[1] == 0)
                    {
                        if (__get(pPosInfo, 1 * 3 * sizeof(size_t)) != 0) //已经锁定了
                        {
                            Infos[2] = __get(pPosInfo, 1 * 3 * sizeof(size_t) + 2 * sizeof(size_t)) + Infos[2] + __get(pInfo, ELCP_MARGIN_TOP * sizeof(size_t)) + __get(pInfo, ELCP_MARGIN_BOTTOM * sizeof(size_t));
                            Infos[0] = 1;
                        }
                    }
                    __set((LPVOID)((size_t)pPosInfo + 3 * 3 * sizeof(size_t)), 0, Infos[0]);
                    __set((LPVOID)((size_t)pPosInfo + 3 * 3 * sizeof(size_t)), sizeof(size_t), Infos[1]);
                    __set((LPVOID)((size_t)pPosInfo + 3 * 3 * sizeof(size_t)), 2 * sizeof(size_t), Infos[2]);
                }
                if (__get(pInfo, 0) != 0 && __get(pInfo, 3 * sizeof(size_t)) != 0 && __get(pInfo, 6 * sizeof(size_t)) != 0 && __get(pInfo, 9 * sizeof(size_t)) != 0) //已经确定整个组件了
                {
                    cNoLockObj = cNoLockObj - 1;
                }
            }
            else
            {
                cNoLockObj = cNoLockObj - 1;
            }
        }
        if (cNoLockObj <= 0)
        {
            break;
        }
    }

    std::vector<size_t> pInfos;
    std::vector<size_t> hObjs;
    HashTable_GetAllKeysAndValues(hHashPosInfos, hObjs, pInfos);
    for (size_t i = 0; i < hObjs.size(); i++)
    {
        HEXOBJ hObj = hObjs[i];
        LPVOID pPosInfo = (LPVOID)pInfos[i];
        LPVOID pInfo = (LPVOID)__get(pPosInfo, 12 * sizeof(size_t));
        INT orgFlags = __get(pPosInfo, 12 * sizeof(size_t) + sizeof(size_t));
        RECT rcObj{0};
        Ex_ObjGetRect(hObj, &rcObj);

        RECT rcTmp{0};
        if (__get((LPVOID)((size_t)pPosInfo + 0 * 3 * sizeof(size_t)), 0) == 0)
        {
            rcTmp.left = rcObj.left;
        }
        else
        {
            rcTmp.left = __get((LPVOID)((size_t)pPosInfo + 0 * 3 * sizeof(size_t)), 2 * sizeof(size_t));
        }
        if (__get((LPVOID)((size_t)pPosInfo + 1 * 3 * sizeof(size_t)), 0) == 0)
        {
            rcTmp.top = rcObj.top;
        }
        else
        {
            rcTmp.top = __get((LPVOID)((size_t)pPosInfo + 1 * 3 * sizeof(size_t)), 2 * sizeof(size_t));
        }
        if (__get((LPVOID)((size_t)pPosInfo + 2 * 3 * sizeof(size_t)), 0) == 0)
        {
            rcTmp.right = rcTmp.left + rcObj.right - rcObj.left;
        }
        else
        {
            rcTmp.right = __get((LPVOID)((size_t)pPosInfo + 2 * 3 * sizeof(size_t)), 2 * sizeof(size_t));
        }
        if (__get((LPVOID)((size_t)pPosInfo + 3 * 3 * sizeof(size_t)), 0) == 0)
        {
            rcTmp.bottom = rcTmp.top + rcObj.bottom - rcObj.top;
        }
        else
        {
            rcTmp.bottom = __get((LPVOID)((size_t)pPosInfo + 3 * 3 * sizeof(size_t)), 2 * sizeof(size_t));
        }

        _layout_move_margin(hObj, &rcTmp, (LPVOID)((size_t)pInfo - 4 * sizeof(size_t)), 15, orgFlags);
    }
    HashTable_Destroy(hHashPosInfos);
}

LRESULT CALLBACK __layout_absolute_proc(layout_s *pLayout, INT nEvent, WPARAM wParam, LPARAM lParam)
{
    if (nEvent == ELN_GETPROPSCOUNT)
    {
        return 0;
    }
    else if (nEvent == ELN_GETCHILDPROPCOUNT)
    {
        /*layout_left="10/10%"
			layout_top="10/10%"
			layout_right="10/10%"
			layout_bottom="10/10%"
			layout_width="10/10%"
			layout_height="10/10%"
			layout_offsetH="10/10%/10*"
			layout_offsetV="10/10%/10*"*/
        return 16;
    }
    else if (nEvent == ELN_UPDATE)
    {
        RECT rcClient{0};
        if (((layout_s *)pLayout)->nBindType_ == HT_OBJECT)
        {
            Ex_ObjGetClientRect(wParam, &rcClient);
        }
        else
        {
            Ex_DUIGetClientRect(wParam, &rcClient);
        }
        LPVOID pInfoa = ((layout_s *)pLayout)->lpLayoutInfo_;
        array_s *hArr = ((layout_s *)pLayout)->hArrChildrenInfo_;
        rcClient.left = rcClient.left + __get(pInfoa, ELP_PADDING_LEFT * sizeof(size_t));
        rcClient.top = rcClient.top + __get(pInfoa, ELP_PADDING_TOP * sizeof(size_t));
        rcClient.right = rcClient.right - __get(pInfoa, ELP_PADDING_RIGHT * sizeof(size_t));
        rcClient.bottom = rcClient.bottom - __get(pInfoa, ELP_PADDING_BOTTOM * sizeof(size_t));
        SIZE szClient{0};
        szClient.cx = rcClient.right - rcClient.left;
        szClient.cy = rcClient.bottom - rcClient.top;
        for (INT i = 1; i <= Array_GetCount(hArr); i++)
        {
            LPVOID pInfo = (LPVOID)Array_GetMember(hArr, i);
            HEXOBJ hObj = __get(pInfo, 0);
            if (hObj == 0)
                continue;
            RECT rcTmp{0};
            Ex_ObjGetRect(hObj, &rcTmp);
            INT ary1 = 0;
            INT ary2 = 0;
            INT ary3 = 0;
            INT ary4 = 0;
            INT nType = __get(pInfo, ELCP_ABSOLUTE_WIDTH_TYPE * sizeof(size_t));
            INT tmp = __get(pInfo, ELCP_ABSOLUTE_WIDTH * sizeof(size_t));
            SIZE szObj{0};
            if (nType == ELCP_ABSOLUTE_TYPE_PS)
            {
                szObj.cx = (FLOAT)tmp / 100 * szClient.cx;
            }
            else if (nType == ELCP_ABSOLUTE_TYPE_PX)
            {
                szObj.cx = tmp;
            }
            else
            {
                szObj.cx = rcTmp.right - rcTmp.left;
            }
            nType = __get(pInfo, ELCP_ABSOLUTE_HEIGHT_TYPE * sizeof(size_t));
            tmp = __get(pInfo, ELCP_ABSOLUTE_HEIGHT * sizeof(size_t));
            if (nType == ELCP_ABSOLUTE_TYPE_PS)
            {
                szObj.cy = (FLOAT)tmp / 100 * szClient.cy;
            }
            else if (nType == ELCP_ABSOLUTE_TYPE_PX)
            {
                szObj.cy = tmp;
            }
            else
            {
                szObj.cy = rcTmp.bottom - rcTmp.top;
            }

            RECT rcObj{0};
            for (INT index = 0; index < 5; index++)
            {
                if (ary1 == 0)
                {
                    ary1 = 1;
                    nType = __get(pInfo, ELCP_ABSOLUTE_LEFT_TYPE * sizeof(size_t));
                    tmp = __get(pInfo, ELCP_ABSOLUTE_LEFT * sizeof(size_t));
                    if (nType == ELCP_ABSOLUTE_TYPE_PS)
                    {
                        rcObj.left = rcClient.left + (FLOAT)tmp / 100 * szClient.cx;
                    }
                    else if (nType == ELCP_ABSOLUTE_TYPE_PX)
                    {
                        rcObj.left = rcClient.left + tmp;
                    }
                    else if (ary3 == 1)
                    {
                        rcObj.left = rcObj.right - szObj.cx;
                    }
                    else
                    {
                        ary1 = 0;
                    }
                }
                if (ary2 == 0)
                {
                    ary2 = 1;
                    nType = __get(pInfo, ELCP_ABSOLUTE_TOP_TYPE * sizeof(size_t));
                    tmp = __get(pInfo, ELCP_ABSOLUTE_TOP * sizeof(size_t));
                    if (nType == ELCP_ABSOLUTE_TYPE_PS)
                    {
                        rcObj.top = rcClient.top + (FLOAT)tmp / 100 * szClient.cy;
                    }
                    else if (nType == ELCP_ABSOLUTE_TYPE_PX)
                    {
                        rcObj.top = rcClient.top + tmp;
                    }
                    else if (ary4 == 1)
                    {
                        rcObj.top = rcObj.bottom - szObj.cy;
                    }
                    else
                    {
                        ary2 = 0;
                    }
                }
                if (ary3 == 0)
                {
                    ary3 = 1;
                    nType = __get(pInfo, ELCP_ABSOLUTE_RIGHT_TYPE * sizeof(size_t));
                    tmp = __get(pInfo, ELCP_ABSOLUTE_RIGHT * sizeof(size_t));
                    if (nType == ELCP_ABSOLUTE_TYPE_PS)
                    {
                        rcObj.right = rcClient.right - (FLOAT)tmp / 100 * szClient.cx;
                    }
                    else if (nType == ELCP_ABSOLUTE_TYPE_PX)
                    {
                        rcObj.right = rcClient.right - tmp;
                    }
                    else if (ary1 == 1)
                    {
                        rcObj.right = rcObj.left + szObj.cx;
                    }
                    else
                    {
                        ary3 = 0;
                    }
                }
                if (ary4 == 0)
                {
                    ary4 = 1;
                    nType = __get(pInfo, ELCP_ABSOLUTE_BOTTOM_TYPE * sizeof(size_t));
                    tmp = __get(pInfo, ELCP_ABSOLUTE_BOTTOM * sizeof(size_t));
                    if (nType == ELCP_ABSOLUTE_TYPE_PS)
                    {
                        rcObj.bottom = rcClient.bottom - (FLOAT)tmp / 100 * szClient.cy;
                    }
                    else if (nType == ELCP_ABSOLUTE_TYPE_PX)
                    {
                        rcObj.bottom = rcClient.bottom - tmp;
                    }
                    else if (ary2 == 1)
                    {
                        rcObj.bottom = rcObj.top + szObj.cy;
                    }
                    else
                    {
                        ary4 = 0;
                    }
                }
                if (ary1 == 1 && ary2 == 1 && ary3 == 1 && ary4 == 1)
                {
                    break;
                }
            }
            if (ary1 == 0)
            {
                rcObj.left = rcTmp.left;
            }
            if (ary2 == 0)
            {
                rcObj.top = rcTmp.top;
            }
            if (ary3 == 0)
            {
                rcObj.right = rcTmp.right;
            }
            if (ary4 == 0)
            {
                rcObj.bottom = rcTmp.bottom;
            }
            nType = __get(pInfo, ELCP_ABSOLUTE_OFFSET_H_TYPE * sizeof(size_t));
            tmp = __get(pInfo, ELCP_ABSOLUTE_OFFSET_H * sizeof(size_t));
            if (nType == ELCP_ABSOLUTE_TYPE_PS)
            {
                rcObj.left = rcObj.left + (FLOAT)tmp / 100 * szClient.cx;
                rcObj.right = rcObj.right + (FLOAT)tmp / 100 * szClient.cx;
            }
            else if (nType == ELCP_ABSOLUTE_TYPE_PX)
            {
                rcObj.left = rcObj.left + tmp;
                rcObj.right = rcObj.right + tmp;
            }
            else if (nType == ELCP_ABSOLUTE_TYPE_OBJPS)
            {
                rcObj.left = rcObj.left + (FLOAT)tmp / 100 * szObj.cx;
                rcObj.right = rcObj.right + (FLOAT)tmp / 100 * szObj.cx;
            }

            nType = __get(pInfo, ELCP_ABSOLUTE_OFFSET_V_TYPE * sizeof(size_t));
            tmp = __get(pInfo, ELCP_ABSOLUTE_OFFSET_V * sizeof(size_t));
            if (nType == ELCP_ABSOLUTE_TYPE_PS)
            {
                rcObj.top = rcObj.top + (FLOAT)tmp / 100 * szClient.cy;
                rcObj.bottom = rcObj.bottom + (FLOAT)tmp / 100 * szClient.cy;
            }
            else if (nType == ELCP_ABSOLUTE_TYPE_PX)
            {
                rcObj.top = rcObj.top + tmp;
                rcObj.bottom = rcObj.bottom + tmp;
            }
            else if (nType == ELCP_ABSOLUTE_TYPE_OBJPS)
            {
                rcObj.top = rcObj.top + (FLOAT)tmp / 100 * szObj.cy;
                rcObj.bottom = rcObj.bottom + (FLOAT)tmp / 100 * szObj.cy;
            }

            _layout_move_margin(hObj, &rcObj, (LPVOID)((size_t)pInfo - 4 * sizeof(size_t)), 15, 0);
        }
    }
    else if (nEvent == ELN_CHECKCHILDPROPVALUE)
    {
        array_s *pChildrenInfo = ((layout_s *)pLayout)->hArrChildrenInfo_;
        LPVOID pInfo = (LPVOID)Array_GetMember(pChildrenInfo, LOWORD(wParam));
        INT nType = HIWORD(wParam);
        if (nType % 2 == 1 && nType >= ELCP_ABSOLUTE_LEFT && nType <= ELCP_ABSOLUTE_OFFSET_V)
        {
            if (__get(pInfo, (nType + 1) * sizeof(size_t)) == ELCP_ABSOLUTE_TYPE_UNKNOWN)
            {
                __set(pInfo, (nType + 1) * sizeof(size_t), ELCP_ABSOLUTE_TYPE_PX);
            }
        }
    }
    return 0;
}

BOOL _layout_addchild(HEXLAYOUT hLayout, HEXOBJ hObj)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    LPVOID pInfo = nullptr;
    obj_s *pObj = NULL;
    BOOL fIsChild = FALSE;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        if (hObj != 0)
        {
            if (pLayout->nBindType_ == HT_OBJECT)
            {
                if (Ex_ObjGetParent(hObj) == pLayout->hBind_)
                {
                    fIsChild = TRUE;
                    
                }
            }
            else
            {
                if (_handle_validate(hObj, HT_OBJECT, (LPVOID *)&pObj, &nError))
                {
                    if (pObj->objParent_ == 0 && pObj->pWnd_->hexdui_ == pLayout->hBind_)
                    {
                        fIsChild = TRUE;
                    }
                }
            }

            if (fIsChild)
            {
                array_s *hArr = pLayout->hArrChildrenInfo_;
                if (_layout_get_child(pLayout, hObj) == 0)
                {
                    size_t nIndex = 0;
                    nIndex = Array_Emum(hArr, &_layout_enum_find_obj, hObj);
                    if (nIndex == 0)
                    {
                        pInfo = Ex_MemAlloc(pLayout->cbInfoLen_);
                        if (pInfo != 0)
                        {
                            pInfo = (LPVOID)((size_t)pInfo + 4 * sizeof(size_t));
                            __set(pInfo, 0, hObj);
                            ((LayoutPROC)pLayout->lpfnProc_)(pLayout, ELN_INITCHILDPROPS, hObj, (size_t)pInfo);
                            nIndex = Array_AddMember(hArr, (size_t)pInfo);
                        }
                        else
                        {
                            nError = ERROR_EX_MEMORY_ALLOC;
                        }
                    }
                }
            }
            else
            {
                nError = ERROR_EX_LAYOUT_NOT_CHILD;
            }
        }
        else
        {
            nError = ERROR_EX_INVALID_OBJECT;
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

BOOL _layout_addchildren(HEXLAYOUT hLayout, BOOL fDesc, EXATOM dwObjClassATOM, INT *nCount)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        array_s *hArr = pLayout->hArrChildrenInfo_;
        EXHANDLE hObj = pLayout->hBind_;
        LPVOID pObj = nullptr;
        if (_handle_validate(hObj, pLayout->nBindType_, (LPVOID *)&pObj, &nError))
        {
            *nCount = 0;
            if (pLayout->nBindType_ == HT_OBJECT)
            {
                hObj = fDesc ? ((obj_s *)pObj)->objChildLast_ : ((obj_s *)pObj)->objChildFirst_;
            }
            else
            {
                hObj = fDesc ? ((wnd_s *)pObj)->objChildLast_ : ((wnd_s *)pObj)->objChildFirst_;
            }
            obj_s *pObj2 = nullptr;
            while (_handle_validate(hObj, HT_OBJECT, (LPVOID *)&pObj2, &nError))
            {
                EXATOM clsAtom = pObj2->pCls_->atomName;
                if ((dwObjClassATOM == 0 || dwObjClassATOM == clsAtom) && clsAtom != ATOM_SYSBUTTON)
                {
                    if (_layout_get_child(pLayout, hObj) == 0)
                    {
                        LPVOID pInfo = Ex_MemAlloc(pLayout->cbInfoLen_);
                        if (pInfo)
                        {
                            pInfo = (LPVOID)((size_t)pInfo + 4 * sizeof(size_t));
                            __set(pInfo, 0, hObj);
                            ((LayoutPROC)pLayout->lpfnProc_)(pLayout, ELN_INITCHILDPROPS, hObj, (size_t)pInfo);
                            Array_AddMember(hArr, (size_t)pInfo);
                            *nCount = *nCount + 1;
                        }
                        else
                        {
                            nError = ERROR_EX_MEMORY_ALLOC;
                        }
                    }
                }
                hObj = fDesc ? pObj2->objPrev_ : pObj2->objNext_;
            }
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

BOOL _layout_deletechildren(HEXLAYOUT hLayout, EXATOM dwObjClassATOM)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        array_s *hArr = pLayout->hArrChildrenInfo_;
        if (hArr != 0)
        {
            if (dwObjClassATOM != 0)
            {
                for (INT i = Array_GetCount(hArr); i >= 1; i--)
                {
                    LPVOID pInfo = (LPVOID)Array_GetMember(hArr, i);
                    obj_s *pObj = nullptr;
                    if (_handle_validate(__get(pInfo, 0), HT_OBJECT, (LPVOID *)&pObj, &nError))
                    {
                        if (dwObjClassATOM == pObj->pCls_->atomName)
                        {
                            Array_DelMember(hArr, i);
                        }
                    }
                }
            }
            else
            {
                Array_Clear(hArr);
            }
        }
        else
        {
            nError = ERROR_EX_LAYOUT_INVALID;
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

BOOL _layout_deletechild(HEXLAYOUT hLayout, HEXOBJ hObj)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        array_s *hArr = pLayout->hArrChildrenInfo_;
        if (hArr != 0)
        {
            size_t nIndex = Array_Emum(hArr, _layout_enum_find_obj, hObj);
            if (nIndex > 0)
            {
                Array_DelMember(hArr, nIndex);
            }
        }
        else
        {
            nError = ERROR_EX_LAYOUT_INVALID;
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

BOOL _layout_getchildproplist(HEXLAYOUT hLayout, HEXOBJ hObj, LPVOID *lpProps)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        array_s *hArr = pLayout->hArrChildrenInfo_;
        size_t nIndex = Array_Emum(hArr, _layout_enum_find_obj, hObj);
        if (nIndex > 0)
        {
            *lpProps = (LPVOID)Array_GetMember(hArr, nIndex);
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

LPVOID _layout_getproplist(HEXLAYOUT hLayout)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    LPVOID pInfo = nullptr;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        pInfo = pLayout->lpLayoutInfo_;
    }
    Ex_SetLastError(nError);
    return pInfo;
}

BOOL _layout_absolute_lock(HEXLAYOUT hLayout, HEXOBJ hObjChild, INT tLeft, INT tTop, INT tRight, INT tBottom, INT tWidth, INT tHeight)
{
    layout_s *pLayout = nullptr;
    INT nError = 0;
    LPVOID pInfo = nullptr;
    if (_handle_validate(hLayout, HT_LAYOUT, (LPVOID *)&pLayout, &nError))
    {
        RECT rcClient{0};
        if (pLayout->nType_ == ELT_ABSOLUTE)
        {
            if (pLayout->nBindType_ == HT_OBJECT)
            {
                Ex_ObjGetClientRect(pLayout->hBind_, &rcClient);
            }
            else
            {
                Ex_DUIGetClientRect(pLayout->hBind_, &rcClient);
            }
            LPVOID pInfo = pLayout->lpLayoutInfo_;
            rcClient.left = rcClient.left + __get(pInfo, ELP_PADDING_LEFT * sizeof(size_t));
            rcClient.top = rcClient.top + __get(pInfo, ELP_PADDING_TOP * sizeof(size_t));
            rcClient.right = rcClient.right - __get(pInfo, ELP_PADDING_RIGHT * sizeof(size_t));
            rcClient.bottom = rcClient.bottom - __get(pInfo, ELP_PADDING_BOTTOM * sizeof(size_t));
            SIZE szClient{0};
            szClient.cx = rcClient.right - rcClient.left;
            szClient.cy = rcClient.bottom - rcClient.top;
            RECT rcObj{0};
            Ex_ObjGetRect(hObjChild, &rcObj);

            if (tLeft == 1) //数值锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_LEFT, rcObj.left - rcClient.left);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_LEFT_TYPE, ELCP_ABSOLUTE_TYPE_PX);
            }
            else if (tLeft == 2) //比例锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_LEFT, (FLOAT)rcObj.left / szClient.cx * 100);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_LEFT_TYPE, ELCP_ABSOLUTE_TYPE_PS);
            }
            else
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_LEFT, 0);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_LEFT_TYPE, ELCP_ABSOLUTE_TYPE_UNKNOWN);
            }

            if (tTop == 1) //数值锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_TOP, rcObj.top - rcClient.top);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_TOP_TYPE, ELCP_ABSOLUTE_TYPE_PX);
            }
            else if (tTop == 2) //比例锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_TOP, (FLOAT)rcObj.top / szClient.cy * 100);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_TOP_TYPE, ELCP_ABSOLUTE_TYPE_PS);
            }
            else
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_TOP, 0);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_TOP_TYPE, ELCP_ABSOLUTE_TYPE_UNKNOWN);
            }

            if (tRight == 1) //数值锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_RIGHT, rcClient.right - rcObj.right);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_RIGHT_TYPE, ELCP_ABSOLUTE_TYPE_PX);
            }
            else if (tRight == 2) //比例锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_RIGHT, (FLOAT)(rcClient.right - rcObj.right) / szClient.cx * 100);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_RIGHT_TYPE, ELCP_ABSOLUTE_TYPE_PS);
            }
            else
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_RIGHT, 0);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_RIGHT_TYPE, ELCP_ABSOLUTE_TYPE_UNKNOWN);
            }

            if (tBottom == 1) //数值锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_BOTTOM, rcClient.bottom - rcObj.bottom);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_BOTTOM_TYPE, ELCP_ABSOLUTE_TYPE_PX);
            }
            else if (tBottom == 2) //比例锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_BOTTOM, (FLOAT)(rcClient.bottom - rcObj.bottom) / szClient.cy * 100);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_BOTTOM_TYPE, ELCP_ABSOLUTE_TYPE_PS);
            }
            else
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_BOTTOM, 0);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_BOTTOM_TYPE, ELCP_ABSOLUTE_TYPE_UNKNOWN);
            }

            if (tWidth == 1) //数值锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_WIDTH, rcObj.right - rcObj.left);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_WIDTH_TYPE, ELCP_ABSOLUTE_TYPE_PX);
            }
            else if (tWidth == 2) //比例锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_WIDTH, (FLOAT)(rcObj.right - rcObj.left) / szClient.cx * 100);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_WIDTH_TYPE, ELCP_ABSOLUTE_TYPE_PS);
            }
            else
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_WIDTH, 0);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_WIDTH_TYPE, ELCP_ABSOLUTE_TYPE_UNKNOWN);
            }

            if (tHeight == 1) //数值锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_HEIGHT, rcObj.bottom - rcObj.top);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_HEIGHT_TYPE, ELCP_ABSOLUTE_TYPE_PX);
            }
            else if (tHeight == 2) //比例锁
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_HEIGHT, (FLOAT)(rcObj.bottom - rcObj.top) / szClient.cy * 100);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_HEIGHT_TYPE, ELCP_ABSOLUTE_TYPE_PS);
            }
            else
            {
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_HEIGHT, 0);
                _layout_setchildprop(hLayout, hObjChild, ELCP_ABSOLUTE_HEIGHT_TYPE, ELCP_ABSOLUTE_TYPE_UNKNOWN);
            }
        }
        else
        {
            nError = ERROR_EX_LAYOUT_UNSUPPORTED_PROP;
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

void _layout_init()
{
    _layout_register(ELT_LINEAR, __layout_linear_proc);
    _layout_register(ELT_FLOW, __layout_flow_proc);
    _layout_register(ELT_PAGE, __layout_page_proc);
    _layout_register(ELT_TABLE, __layout_table_proc);
    _layout_register(ELT_RELATIVE, __layout_relative_proc);
    _layout_register(ELT_ABSOLUTE, __layout_absolute_proc);
}